import { CanActivate, ExecutionContext, Inject, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PermissionData, PermissionStrategyEnum } from '../decorators/permission.decorator';
import { PERMISSION_KEY } from '../constants/decorator.constant';
import { UserService } from 'src/modules/user/user.service';
import { ApiException } from '../exceptions/api-exception';
import { ADMIN_USER_ID } from 'src/common/constants/admin.constant';
import { RedisService } from 'src/modules/redis/redis.service';
import { USER_PERMISSION_KEY } from '../constants/redis.contant';

/**
 * 权限认证守卫
 * 用于验证用户是否具有访问特定路由的权限
 */
@Injectable()
export class PermissionAuthGuard implements CanActivate {
  constructor(
    private readonly reflector: Reflector, // 用于获取路由元数据
    @Inject(UserService)
    private readonly userService: UserService, // 用户服务
    @Inject(RedisService)
    private readonly redis: RedisService // Redis服务，用于缓存权限
  ) {}

  /**
   * 权限验证方法
   * @param context - 执行上下文
   * @returns {Promise<boolean>} - 是否具有权限
   */
  async canActivate(context: ExecutionContext) {
    // 获取路由上的权限装饰器数据
    const permissionData = this.reflector.getAllAndOverride<PermissionData>(PERMISSION_KEY, [
      context.getHandler(),
      context.getClass()
    ]);
    // console.log('permissions.auth.guard permissionData :>> ', permissionData);

    let result = false;

    // 如果没有权限要求，直接放行
    if (!permissionData || permissionData.permissions.length === 0) return true;

    // 获取请求中的用户信息
    const request = context.switchToHttp().getRequest();
    const userId = request.user?.userId;
    // console.log('request :>> ', request);

    // 超级管理员直接放行
    if (userId === ADMIN_USER_ID) return true;

    // 获取用户权限码集合
    let userPermissionCodes = [];
    // 尝试从Redis缓存获取权限
    const cachePermissionsStr = await this.redis.get(`${USER_PERMISSION_KEY}:${userId}`);
    // console.log('cachePermissionsStr :>> ', cachePermissionsStr);

    if (!cachePermissionsStr) {
      // 缓存未命中，从数据库获取权限
      const userInfo = await this.userService.getCurrentUserInfo(userId);
      userPermissionCodes = userInfo.permissions || [];
    } else {
      // 使用缓存的权限数据
      userPermissionCodes = JSON.parse(cachePermissionsStr);
    }

    // 根据权限策略验证权限
    if (permissionData.strategy === PermissionStrategyEnum.OR) {
      // OR策略：只要满足其中一个权限即可
      result = permissionData.permissions.some((item) => userPermissionCodes.includes(item));
    } else {
      // AND策略：必须满足所有权限
      result = permissionData.permissions.every((item) => userPermissionCodes.includes(item));
    }

    // 权限验证失败，抛出异常
    if (!result) throw new ApiException('暂无权限访问，请联系管理员');

    return result;
  }
}
